package model

import (
    "encoding/json"
    "errors"
    "git.inspur.com/x/models"
)

type FuncVersion struct {
    VersionId     string `xorm:"'id' pk"`
    FuncId        string
    FuncName      string
    GroupId       string
    VersionName   string `xorm:"'name'"`
    Description   string
    MemorySize    int
    GpuNum        int
    GpuType       string
    Envs          []Environment `xorm:"json"`
    Timeout       int
    Handler       string
    Concurrency   int
    ReserveNumber int
    EnablePublic  int         `json:"enablePublic" valid:"-" xorm:"'is_enable_public'"` // 是否开启公网
    EnableVpc     int         `json:"enableVpc" valid:"-" xorm:"'is_enable_vpc'"`
    VpcInfo       VpcInfo     `json:"vpcInfo" valid:"-" xorm:"json"`
    DeleteTime    models.Time `xorm:"deleted" valid:"-"`
    CreateTime    models.Time `xorm:"created"`
    UpdateTime    models.Time `xorm:"updated"`

    ContainerImage   string `json:"containerImage" valid:"-" xorm:"container_image"`
    ContainerCommand string `json:"containerCommand" valid:"-" xorm:"container_command"`
    ContainerArgs    string `json:"containerArgs" valid:"-" xorm:"container_args"`
    ContainerPort    string `json:"containerPort" valid:"custom-container-port~valid.func.port" xorm:"container_port"`

    InitHandler   string   `json:"initializeHandler" valid:"-" xorm:"init_handler"`
    InitTimeout   int      `json:"initializeTimeout" valid:"-" xorm:"init_timeout"`
    BindingLayers []string `json:"bindingLayers" valid:"-" xorm:"json"`
}

type Version struct {
    Description string `json:"description" valid:"length(0|2000)~函数描述长度不能超过2000,optional" `
}

func (f FuncVersion) TableName() string {
    return "fcs_func_version"
}

func CreateVersion(version *FuncVersion) (*FuncVersion, error) {
    if _, err := models.Engine.Insert(version); err != nil {
        _ = logger.Error("CreateVersion: insert error: %v", err)
        return nil, err
    }
    return version, nil
}

func GetVersion(funcId, versionName string) (*FuncVersion, error) {
    funcVersion := new(FuncVersion)
    has, err := models.Engine.Where("func_id=?", funcId).And("name=?", versionName).Get(funcVersion)
    if err != nil {
        _ = logger.Error("GetVersion: get funcVersion error %v", err)
        return nil, err
    }
    if !has {
        _ = logger.Warn("GetVersion: did not find func_version, versionName=%v", versionName)
        return nil, errors.New("didn't find func_version")
    }
    return funcVersion, nil
}

func GetVersionList(funcId string) ([]*FuncVersion, error) {
    versionList := make([]*FuncVersion, 0)
    err := models.Engine.Where("func_id=?", funcId).Desc("create_time").Find(&versionList)
    if err != nil {
        _ = logger.Error("GetVersionList: get funcInfo list error %v", err)
        return nil, err
    }
    return versionList, nil
}

func GetLatestVersion(funcId string) (*FuncVersion, error) {
    funcVersion := new(FuncVersion)
    has, err := models.Engine.Where("func_id=?", funcId).And("name=?", FunctionLatestVersion).Get(funcVersion)
    if err != nil {
        _ = logger.Error("GetLatestVersion: get funcVersion error %v", err)
        return nil, err
    }
    if !has {
        _ = logger.Warn("GetLatestVersion: did not find func_version, funcId=%v", funcId)
        return nil, errors.New("didn't find func_version")
    }
    return funcVersion, nil
}

func GetNewestVersion(funcId string) (*FuncVersion, error) {
    funcVersion := new(FuncVersion)
    has, err := models.Engine.Where("func_id=?", funcId).Desc("update_time").Get(funcVersion)
    if err != nil {
        _ = logger.Error("GetNewestVersion: get funcVersion error %v", err)
        return nil, err
    }
    if !has {
        _ = logger.Warn("GetNewestVersion: did not find func_version, funcId=%v", funcId)
        return nil, errors.New("didn't find func_version")
    }
    return funcVersion, nil
}

func UpdateFuncVersion(version *FuncVersion) (*FuncVersion, error) {
    line, err := models.Engine.ID(version.VersionId).AllCols().Update(version)
    if err != nil {
        _ = logger.Error("UpdateFuncInfo: update funcVersion error %v", err)
        return nil, err
    }
    // 特殊处理，xorm不会更新字段的默认值
    if version.ReserveNumber == 0 || version.EnablePublic == 0 || version.EnableVpc == 0 || len(version.Envs) == 0 || version.GpuNum == 0 {
        if len(version.Envs) == 0 {
            _, err = models.Engine.Table(new(FuncVersion)).ID(version.VersionId).
                Update(map[string]interface{}{
                    "reserve_number":   version.ReserveNumber,
                    "is_enable_public": version.EnablePublic,
                    "is_enable_vpc":    version.EnableVpc,
                    "gpu_num":          version.GpuNum,
                    "envs":             "[]",
                })
        } else {
            _, err = models.Engine.Table(new(FuncVersion)).ID(version.VersionId).
                Update(map[string]interface{}{
                    "reserve_number":   version.ReserveNumber,
                    "is_enable_public": version.EnablePublic,
                    "is_enable_vpc":    version.EnableVpc,
                    "gpu_num":          version.GpuNum,
                })
        }

        if err != nil {
            _ = logger.Error("UpdateFuncInfo: update funcVersion reverse num error %v", err)
            return nil, err
        }
        if version.EnableVpc == 0 {
            _, err = models.Engine.Table(new(FuncVersion)).ID(version.VersionId).
                Update(map[string]interface{}{
                    "vpc_info": "{}",
                })
            if err != nil {
                _ = logger.Error("UpdateFuncInfo: update funcVersion vpc_info error %v", err)
            }
        }
    }
    if line == 0 {
        versionJson, _ := json.Marshal(version)
        _ = logger.Warn("UpdateFuncVersion: did not update func_version, funcInfo=%v", string(versionJson))
        return nil, errors.New("update func_version failed")
    }
    return version, nil
}

func DeleteFunctionVersionByFunc(funcId string) (int64, error) {
    line, err := models.Engine.Table(new(FuncVersion)).Where("func_id=?", funcId).Delete(new(FuncVersion))
    if err != nil {
        _ = logger.Error("DeleteFunctionVersionByFunc: delete funcVersion error %v", err)
        return 0, err
    }
    if line == 0 {
        _ = logger.Warn("DeleteFunctionVersionByFunc: did not update func_version, funcId=%v", funcId)
        return 0, errors.New("delete func_version failed")
    }
    return line, err
}

func DeleteVersion(funcId, versionName string) error {
    line, err := models.Engine.Where("func_id=?", funcId).And("name=?", versionName).Delete(&FuncVersion{})
    if err != nil {
        _ = logger.Error("DeleteVersion: delete version error %v", err)
        return err
    }
    if line == 0 {
        _ = logger.Warn("DeleteVersion: did not delete version, funcId=%s, versionName=%s", funcId, versionName)
        return errors.New("delete func_version failed")
    }
    return nil
}

// CheckLayerIsUsed 检查是否有层绑定在函数上
func CheckLayerIsUsed(layerVersionId string) (bool, error) {
    f := &FuncVersion{}
    return models.Engine.Where("binding_layers like ?", "%"+layerVersionId+"%").Exist(f)
}
